<!DOCTYPE html>
<html lang=\"en\" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset=\"utf-8\">
    <title>XMRigCC Dashboard</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.5.0/css/buttons.bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/select/1.2.5/css/select.dataTables.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.2/css/bootstrap-select.min.css">
    <link rel="stylesheet" href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css">
    <link rel="stylesheet" href="https://cdn.datatables.net/rowgroup/1.1.1/css/rowGroup.dataTables.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">

    <style>
        html {
            scroll-behavior: smooth;
        }

        /* width */
        ::-webkit-scrollbar {
            width: 10px;
            height: 10px;
        }

        /* Track */
        ::-webkit-scrollbar-track {
            background: rgba(255, 255, 255, 0.7);
        }

        /* Handle */
        ::-webkit-scrollbar-thumb {
            background: rgba(0, 0, 0, 0.5);
            border-radius: 1rem;
        }

        /* Handle on hover */
        ::-webkit-scrollbar-thumb:hover {
            background: rgba(0, 0, 0, 0.7);
        }

        #loader-parent {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-content: center;
            align-items: center;
            z-index: 9999;
        }

        .loader,
        .loader:before,
        .loader:after {
            background: #02ABE4;
            -webkit-animation: load1 1s infinite ease-in-out;
            animation: load1 1s infinite ease-in-out;
            width: 1em;
            height: 4em;
            border-radius: 2rem;

        }

        .dataTables_empty {
            color: black;
        }

        .loader {
            color: #02ABE4;
            text-indent: -9999em;
            margin: 88px auto;
            position: relative;
            font-size: 11px;
            -webkit-transform: translateZ(0);
            -ms-transform: translateZ(0);
            transform: translateZ(0);
            -webkit-animation-delay: -0.16s;
            animation-delay: -0.16s;
        }

        .loader:before,
        .loader:after {
            position: absolute;
            top: 0;
            content: '';
        }

        .loader:before {
            left: -1.5em;
            -webkit-animation-delay: -0.32s;
            animation-delay: -0.32s;
        }

        .loader:after {
            left: 1.5em;
        }

        @-webkit-keyframes load1 {
            0%,
            80%,
            100% {
                box-shadow: 0 0;
                height: 4em;
            }
            40% {
                box-shadow: 0 -2em;
                height: 5em;
            }
        }

        @keyframes load1 {
            0%,
            80%,
            100% {
                box-shadow: 0 0;
                height: 4em;
            }
            40% {
                box-shadow: 0 -2em;
                height: 5em;
            }
        }


        .right {
            text-align: right;
        }

        .left {
            text-align: left;
        }

        .rowPadded {
            padding-top: 15px;
        }

        .center {
            text-align: center;
            padding-bottom: 50pt
        }

        .center-tab {
            text-align: center;
            vertical-align: middle;
        }

        .online {
            color: green !important
        }

        .offline {
            color: red !important
        }

        .paused {
            color: yellow !important
        }

        .toggle {
            border-radius: 2px;
        }

        .toggle .toggle-handle {
            border-radius: 2px;
        }

        form label {
            display: block;
            margin-bottom: 5px;
            text-align: left;
        }

        form label span {
            display: inline-block;
            margin-left: .5rem;
            text-align: left;
        }

        form label input {
            vertical-align: top;
        }

        body {
            font-family: 'Poppins', sans-serif;
            /* font-size: 16px; */
            /* line-height: 24px; */
            /* font-weight: 400; */
            color: #212112;
            background-color: #fff;
            overflow-x: hidden;
            /* transition: all 200ms linear;  */
        }

        ::selection {
            color: #fff;
            background-color: #02ABE4;
        }

        ::-moz-selection {
            color: #fff;
            background-color: #02ABE4;
        }


        /* #Navigation
        ================================================== */
        .nav-container {
            width: 90%;
            margin: auto;
        }

        .start-header {
            /* opacity: 1; */
            /* transform: translateY(0%); */
            padding-bottom: 10px;
            box-shadow: 0 10px 30px 0 rgba(138, 155, 165, 0.15);
            -webkit-transition: all 0.3s ease-out;
            transition: all 0.3s ease-out;
        }

        .start-style {
            padding-bottom: 2px;
            /* padding-bottom: 10px; */
        }

        .nav-button {
            margin-right: 4rem;
            list-style-type: none;
        }

        #light-mode {
            fill: #02ABE4;
        }

        .start-header.scroll-on {
            box-shadow: 0 5px 10px 0 rgba(138, 155, 165, 0.15);
            /* padding-top: 10px; */
            -webkit-transition: all 0.3s ease-out;
            transition: all 0.3s ease-out;
        }

        .navbar-brand img {
            height: 50px;
            width: auto;
            /* display: block; */
            /* transform: translateY(-30%); */
            -webkit-transition: all 0.3s ease-out;
            transition: all 0.3s ease-out;
        }

        .start-header.scroll-on .navbar-brand img {
            /* height: 60px; */
            transform: scale(1.05);
            /* transform: translateY(-40%); */
            -webkit-transition: all 0.3s ease-out;
            transition: all 0.3s ease-out;
        }

        .navigation-wrap {
            font-size: 16px;
            /* line-height: 24px; */
            font-weight: 400;
            position: sticky;
            width: 100%;
            top: 0;
            left: 0;
            z-index: 1000;
            -webkit-transition: all 0.3s ease-out;
            transition: all 0.3s ease-out;
        }

        .navbar {
            padding: 0;
        }

        .dark-mode-logo {
            filter: brightness(0) invert(1);
        }

        .navbar-toggler {
            float: right;
            border: none;
            padding-right: 0;
        }

        .navbar-toggler:active,
        .navbar-toggler:focus {
            outline: none;
        }

        .navbar-light .navbar-toggler-icon {
            width: 24px;
            height: 17px;
            background-image: none;
            position: relative;
            border-bottom: 1px solid #000;
            transition: all 300ms linear;
        }

        .navbar-light .navbar-toggler-icon:after,
        .navbar-light .navbar-toggler-icon:before {
            width: 24px;
            position: absolute;
            height: 1px;
            background-color: #000;
            top: 0;
            left: 0;
            content: '';
            z-index: 2;
            transition: all 300ms linear;
        }

        .navbar-light .navbar-toggler-icon:after {
            top: 8px;
        }

        .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon:after {
            transform: rotate(45deg);
        }

        .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon:before {
            transform: translateY(8px) rotate(-45deg);
        }

        .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon {
            border-color: transparent;
        }

        .nav-link {
            color: #212121 !important;
            font-weight: 500;
            transition: all 200ms linear;
            text-decoration: none !important;
            position: relative;
            padding: 5px 0 !important;
            display: inline-block;
        }

        .nav-link:hover {
            text-decoration: none !important;
        }

        .nav-item:hover .nav-link {
            color: #02ABE4 !important;
        }

        .nav-item.active .nav-link {
            color: #777 !important;
        }

        .nav-item:after {
            position: absolute;
            bottom: -5px;
            left: 0;
            width: 100%;
            height: 2px;
            content: '';
            background-color: #02ABE4;
            opacity: 0;
            transition: all 200ms linear;
        }

        .nav-item:hover:after {
            bottom: 0;
            opacity: 1;
        }

        .nav-item.active:hover:after {
            opacity: 0;
        }

        .nav-item {
            position: relative;
            transition: all 200ms linear;
        }

        /* #Primary style
        ================================================== */

        .container {
            height: 60px;
        }

        .bg-light {
            background-color: #fff !important;
            transition: all 200ms linear;
        }

        .section {
            position: relative;
            width: 100%;
            display: block;
        }

        .over-hide {
            overflow: hidden;
        }

        .absolute-center {
            position: absolute;
            top: 50%;
            left: 0;
            width: 100%;
            margin-top: 40px;
            transform: translateY(-50%);
            z-index: 20;
        }

        h1 {
            font-size: 48px;
            line-height: 1.2;
            font-weight: 700;
            color: #212112;
            text-align: center;
        }

        p {
            text-align: center;
            margin: 0;
            padding-top: 10px;
            opacity: 1;
            transform: translate(0);
            transition: all 300ms linear;
            transition-delay: 1700ms;
        }

        body.xmrigCC p {
            opacity: 0;
            transform: translateY(40px);
            transition-delay: 1700ms;
        }

        h1 span {
            display: inline-block;
            transition: all 300ms linear;
            opacity: 1;
            transform: translate(0);
        }

        body.xmrigCC h1 span:nth-child(1) {
            opacity: 0;
            transform: translateY(-20px);
        }

        body.xmrigCC h1 span:nth-child(2) {
            opacity: 0;
            transform: translateY(-30px);
        }

        body.xmrigCC h1 span:nth-child(3) {
            opacity: 0;
            transform: translateY(-50px);
        }

        body.xmrigCC h1 span:nth-child(4) {
            opacity: 0;
            transform: translateY(-10px);
        }

        body.xmrigCC h1 span:nth-child(5) {
            opacity: 0;
            transform: translateY(-50px);
        }

        body.xmrigCC h1 span:nth-child(6) {
            opacity: 0;
            transform: translateY(-20px);
        }

        body.xmrigCC h1 span:nth-child(7) {
            opacity: 0;
            transform: translateY(-40px);
        }

        body.xmrigCC h1 span:nth-child(8) {
            opacity: 0;
            transform: translateY(-10px);
        }

        body.xmrigCC h1 span:nth-child(9) {
            opacity: 0;
            transform: translateY(-30px);
        }

        body.xmrigCC h1 span:nth-child(10) {
            opacity: 0;
            transform: translateY(-20px);
        }

        h1 span:nth-child(1) {
            transition-delay: 1000ms;
        }

        h1 span:nth-child(2) {
            transition-delay: 700ms;
        }

        h1 span:nth-child(3) {
            transition-delay: 900ms;
        }

        h1 span:nth-child(4) {
            transition-delay: 800ms;
        }

        h1 span:nth-child(5) {
            transition-delay: 1000ms;
        }

        h1 span:nth-child(6) {
            transition-delay: 700ms;
        }

        h1 span:nth-child(7) {
            transition-delay: 900ms;
        }

        h1 span:nth-child(8) {
            transition-delay: 800ms;
        }

        h1 span:nth-child(9) {
            transition-delay: 600ms;
        }

        h1 span:nth-child(10) {
            transition-delay: 700ms;
        }

        body.xmrigCC h1 span:nth-child(11) {
            opacity: 0;
            transform: translateY(30px);
        }

        body.xmrigCC h1 span:nth-child(12) {
            opacity: 0;
            transform: translateY(50px);
        }

        body.xmrigCC h1 span:nth-child(13) {
            opacity: 0;
            transform: translateY(20px);
        }

        body.xmrigCC h1 span:nth-child(14) {
            opacity: 0;
            transform: translateY(30px);
        }

        body.xmrigCC h1 span:nth-child(15) {
            opacity: 0;
            transform: translateY(50px);
        }

        h1 span:nth-child(11) {
            transition-delay: 1300ms;
        }

        h1 span:nth-child(12) {
            transition-delay: 1500ms;
        }

        h1 span:nth-child(13) {
            transition-delay: 1400ms;
        }

        h1 span:nth-child(14) {
            transition-delay: 1200ms;
        }

        h1 span:nth-child(15) {
            transition-delay: 1450ms;
        }

        #switch,
        #circle {
            cursor: pointer;
            -webkit-transition: all 300ms linear;
            transition: all 300ms linear;
        }

        #switch {
            width: 40px;
            height: 6px;
            border: 2px solid #02ABE4;
            border-radius: 27px;
            background: #000;
            position: relative;
            top: 30%;
            left: 50%;
            display: block;
            margin: auto;
            text-align: center;
            /* opacity: 1; */
            /* transform: translate(100%,50%); */
        }

        #circle {
            position: absolute;
            top: -8px;
            left: -13px;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #000;
        }

        .switched {
            border-color: #fff !important;
            background: #02ABE4 !important;
        }

        .switched #circle {
            left: 30px;
            box-shadow: 0 4px 4px rgba(26, 53, 71, 0.25), 0 0 0 1px rgba(26, 53, 71, 0.07);
            background: #fff;
        }

        .nav-item .dropdown-menu {
            transform: translate3d(0, 10px, 0);
            visibility: hidden;
            opacity: 0;
            max-height: 0;
            display: block;
            padding: 0;
            margin: 0;
            transition: all 200ms linear;
        }

        .nav-item.show .dropdown-menu {
            opacity: 1;
            visibility: visible;
            max-height: 999px;
            transform: translate3d(0, 0px, 0);
        }

        .contact-item {
            color: #fff;
            right: 50px;
            font-size: 28px;
            padding: 5px !important;
            transition: all 200ms linear;
        }

        .dropdown-menu {
            padding: 10px !important;
            margin: 0;
            font-size: 13px;
            letter-spacing: 1px;
            color: #212121;
            background-color: #fcfaff;
            border: none;
            border-radius: 3px;
            box-shadow: 0 5px 10px 0 rgba(138, 155, 165, 0.15);
            /* transition: all 200ms linear; */
        }

        .dropdown-toggle::after {
            display: none;
        }

        .dropdown-item {
            /* padding: 3px 15px; */
            color: #212121;
            border-radius: 2px;
            width: 100%;
            right: 50px;
            padding: 5px !important;
            transition: all 200ms linear;
        }

        .dropdown-item:hover,
        .dropdown-item:focus {
            color: #fff;
            background-color: rgba(2, 171, 228, 0.1);
        }

        body.dark {
            color: #fff;
            background-color: #1f2029;
        }

        /* body.dark .navbar-brand img{
          filter: brightness(100%);
        } */
        body.dark h1 {
            color: #fff;
        }

        body.dark h1 span {
            transition-delay: 0ms !important;
        }

        body.dark p {
            color: #fff;
            transition-delay: 0ms !important;
        }

        body.dark .bg-light {
            background-color: #14151a !important;
        }

        body.dark .start-header {
            box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.15);
        }

        body.dark .start-header.scroll-on {
            box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15);
        }

        body.dark .nav-link {
            color: #fff !important;
        }

        body.dark .nav-item.active .nav-link {
            color: #999 !important;
        }

        body.dark .dropdown-menu {
            color: #fff;
            background-color: #1f2029;
            box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.25);
        }

        body.dark .dropdown-item {
            color: #fff;
        }

        body.dark .navbar-light .navbar-toggler-icon {
            border-bottom: 1px solid #fff;
        }

        body.dark .navbar-light .navbar-toggler-icon:after,
        body.dark .navbar-light .navbar-toggler-icon:before {
            background-color: #fff;
        }

        body.dark .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon {
            border-color: transparent;
        }


        /* #Media
        ================================================== */

        @media (max-width: 767px) {
            h1 {
                font-size: 38px;
            }

            .nav-item:after {
                display: none;
            }

            .nav-item::before {
                position: absolute;
                display: block;
                top: 15px;
                left: 0;
                width: 11px;
                height: 1px;
                content: "";
                border: none;
                background-color: #000;
                /* vertical-align: 0; */
            }

            .dropdown-toggle::after {
                position: absolute;
                display: block;
                top: 10px;
                left: -23px;
                width: 1px;
                height: 11px;
                content: "";
                border: none;
                background-color: #000;
                /* vertical-align: 0; */
                transition: all 200ms linear;
            }

            .dropdown-toggle[aria-expanded="true"]::after {
                transform: rotate(90deg);
                opacity: 0;
            }

            .dropdown-menu {
                padding: 0 !important;
                background-color: transparent;
                box-shadow: none;
                transition: all 200ms linear;
            }

            .dropdown-toggle[aria-expanded="true"] + .dropdown-menu {
                margin-top: 10px !important;
                margin-bottom: 20px !important;
            }

            body.dark .nav-item::before {
                background-color: #fff;
            }

            body.dark .dropdown-toggle::after {
                background-color: #fff;
            }

            body.dark .dropdown-menu {
                background-color: transparent;
                box-shadow: none;
            }
        }

        .dialog-close-scheme {
            filter: invert(1) grayscale(100%) brightness(200%);
            opacity: 1;
        }


        #light-mode {
            color: #02ABE4;
        }

        .theme-icon {
            width: 2rem;
            position: relative;
            top: 30%;
            display: block;
            margin: auto;
            text-align: center;
            /* fill:  */
        }

        #theme-handle {
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .logo {
            position: absolute;
            bottom: 30px;
            right: 30px;
            display: block;
            z-index: 100;
            /* transition: all 250ms linear; */
        }

        .logo img {
            height: 26px;
            width: auto;
            display: block;
            filter: brightness(10%);
            /* transition: all 250ms linear; */
        }

        body.dark .logo img {
            filter: brightness(100%);
        }

        .navbar-expand-md {
            display: flex;
            justify-content: flex-start;
            align-items: center;
        }

        .navbar-collapse {
            position: absolute;
            right: 0;
            top: 35%;
            /* transform: translateY(-50%); */
        }

        .table {
            display: block;
            overflow-x: auto;
            white-space: nowrap;
            border: none;
        }

        table > thead > tr > th, table > tfoot > tr > th {
            font-weight: 500;
        }

        table > tbody > tr > td {
            font-weight: 500;
        }

        table.dataTable tbody tr {
            color: #000 !important;
            background-color: #fff;
        }

        #contact > a > div {
            display: flex;
            align-items: center;
        }

        .setting-table {
            padding: 20px;
            padding-left: 0 !important;
        }

        .setting-text {
            white-space: nowrap;
            font-size: 14px;
            color: #02ABE4;
        }
    </style>

    <link href=""
          rel="icon" type="image/x-icon">


</head>

<body class="xmrigCC">
<!-- loading screen-->
<div id="loader-parent">
    <div class="loader"></div>
</div>
<!-- loading screen-->
<div class="navigation-wrap bg-light start-header start-style">
    <div class="nav-container">


        <nav class="navbar navbar-light">

            <div class="navbar-brand">
                <img src=""/>
            </div>
            <div style="display: flex; flex-direction: row; position: absolute; left: 48%;top: 35%;">
                <a class="contact-item nav-link" href="https://github.com/Bendr0id/xmrigCC" target="_blank">
                    <div>
                        <i class="fa fa-github"></i>
                    </div>
                </a>
                &nbsp;
                <a class="contact-item nav-link" href="https://t.me/XMRigCC" target="_blank">
                    <div>
                        <i class="fa fa-telegram"></i>
                    </div>
                </a>
                &nbsp;
                <a class="contact-item nav-link" href="https://discord.gg/r3rCKTB" target="_blank">
                    <div>
                        <i class="fab fa-discord"></i>
                    </div>
                </a>
                &nbsp;
                <a class="contact-item nav-link" href="https://twitter.com/XMRigCC" target="_blank">
                    <div>
                        <i class="fa fa-twitter"></i>
                    </div>
                </a>
                &nbsp;
                <a class="contact-item nav-link" href="https://www.reddit.com/user/BenDr0id/" target="_blank">
                    <div><i class="fa fa-reddit"></i>
                    </div>
                </a>
            </div>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">

                <ul class="navbar-nav navbar-expand-md ml-auto py-4 py-md-0">

                    <li class="nav-item nav-button">
                        <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button"
                           aria-haspopup="true" aria-expanded="false">
                            <i class="fa fa-wrench"></i>&nbsp;Settings
                        </a>
                        <div class="dropdown-menu">
                            <form style="width: auto">
                                <table style="display: table;">
                                    <tr>
                                        <td>
                                            <span class="setting-text">Hide offline miners</span>
                                        </td>
                                        <td>
                                            <input id="hideOffline" type="checkbox" checked data-toggle="toggle"
                                                   data-size="mini"
                                                   data-onstyle="success" data-offstyle="danger"/>
                                        </td>
                                    </tr>
                                    <tr class="setting-table">
                                        <td class="setting-table">
                                            <span class="setting-text">Notify when miner went offline</span>
                                        </td>
                                        <td>
                                            <input id="showOfflineNotification" type="checkbox" checked
                                                   data-toggle="toggle" data-size="mini" data-onstyle="success"
                                                   data-offstyle="danger"/>
                                        </td>
                                    </tr>
                                    <tr>
                                        <td>
                                            <span class="setting-text">Group by Algo</span>
                                        </td>
                                        <td>
                                            <input id="groupByAlgo" type="checkbox" data-toggle="toggle" checked
                                                   data-size="mini"
                                                   data-onstyle="success" data-offstyle="danger"/>
                                        </td>
                                    </tr>
                                </table>
                            </form>
                        </div>
                    </li>

                    <span id="light-mode">
                                    <svg class="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                                        <path d="M256 159.1c-53.02 0-95.1 42.98-95.1 95.1S202.1 351.1 256 351.1s95.1-42.98 95.1-95.1S309 159.1 256 159.1zM509.3 347L446.1 255.1l63.15-91.01c6.332-9.125 1.104-21.74-9.826-23.72l-109-19.7l-19.7-109c-1.975-10.93-14.59-16.16-23.72-9.824L256 65.89L164.1 2.736c-9.125-6.332-21.74-1.107-23.72 9.824L121.6 121.6L12.56 141.3C1.633 143.2-3.596 155.9 2.736 164.1L65.89 256l-63.15 91.01c-6.332 9.125-1.105 21.74 9.824 23.72l109 19.7l19.7 109c1.975 10.93 14.59 16.16 23.72 9.824L256 446.1l91.01 63.15c9.127 6.334 21.75 1.107 23.72-9.822l19.7-109l109-19.7C510.4 368.8 515.6 356.1 509.3 347zM256 383.1c-70.69 0-127.1-57.31-127.1-127.1c0-70.69 57.31-127.1 127.1-127.1s127.1 57.3 127.1 127.1C383.1 326.7 326.7 383.1 256 383.1z"/>
                                    </svg>
                                </span>
                    <li class="nav-button">
                        <div id="switch">
                            <div id="circle"></div>
                        </div>
                    </li>
                    <span id="dark-mode"><svg svg class="theme-icon" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
                                    width="45.74px" height="45.74px" viewBox="0 0 45.74 45.74" style="enable-background:new 0 0 45.74 45.74;" xml:space="preserve"
                                   >
                               <g>
                                   <g>
                                       <g>
                                           <g>
                                               <g>
                                                   <path d="M12.2,15.267c0-3.322,0.896-6.43,2.448-9.113c0.376-0.649-0.191-1.451-0.918-1.265
                                                       C5.35,7.041-0.711,14.961,0.067,24.179c0.736,8.701,7.768,15.803,16.463,16.617c6.033,0.565,11.517-1.811,15.221-5.848
                                                       c0.5-0.546,0.073-1.432-0.666-1.401c-0.196,0.009-0.395,0.013-0.594,0.013C20.389,33.56,12.2,25.371,12.2,15.267z"/>
                                               </g>
                                           </g>
                                           <g>
                                               <path d="M23.144,5.6l0.917,2.633l2.788,0.061c0.354,0.008,0.498,0.456,0.218,0.669l-2.221,1.687l0.805,2.669
                                                   c0.104,0.338-0.279,0.614-0.568,0.414l-2.292-1.59l-2.29,1.59c-0.29,0.201-0.669-0.076-0.569-0.414l0.805-2.669l-2.221-1.687
                                                   c-0.28-0.213-0.134-0.661,0.218-0.669l2.788-0.061L22.44,5.6C22.556,5.267,23.027,5.267,23.144,5.6z"/>
                                           </g>
                                           <g>
                                               <path d="M40.26,26.44l0.881,2.53l2.679,0.057c0.389,0.009,0.549,0.502,0.24,0.737l-2.134,1.621l0.772,2.564
                                                   c0.111,0.371-0.309,0.677-0.627,0.454l-2.201-1.527l-2.2,1.527c-0.318,0.223-0.739-0.083-0.626-0.454l0.772-2.564l-2.133-1.621
                                                   c-0.31-0.234-0.149-0.729,0.238-0.737l2.679-0.057l0.884-2.53C39.612,26.074,40.131,26.074,40.26,26.44z"/>
                                           </g>
                                           <g>
                                               <path d="M39.926,8.098l1.325,3.799l4.021,0.086c0.452,0.01,0.639,0.584,0.278,0.858l-3.204,2.434l1.162,3.853
                                                   c0.131,0.433-0.356,0.788-0.729,0.529l-3.306-2.294l-3.305,2.294c-0.372,0.259-0.86-0.097-0.729-0.529l1.161-3.853l-3.205-2.434
                                                   c-0.358-0.273-0.172-0.849,0.279-0.858l4.022-0.086l1.324-3.799C39.173,7.672,39.776,7.672,39.926,8.098z"/>
                                           </g>
                                       </g>
                                   </g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               <g>
                               </g>
                               </svg>
                               </span>
                </ul>
            </div>


        </nav>
    </div>
</div>
</div>
<br/>
<div style="width: 96%; margin:0 auto;">
    <div id="updateNotificationBar"></div>
    <div id="notificationBar"></div>
    <div id="statusBar"></div>

    <form style="padding-bottom: 25px">
        <button id="resetClientStatus" type="button" class="btn btn-danger fa fa-trash-o"> Reset ClientStatusList
        </button>
    </form>

    <table id="clientStatusList" class="table table-striped table-bordered" cellspacing="0" width="100%">
        <thead>
        <tr>
            <th class="center" width="2%"><i class="fa fa-square-o" id="selectAllTop"></i></th>
            <th>Worker Id</th>
            <th>Version</th>
            <th>Pool</th>
            <th>User</th>
            <th>Password</th>
            <th>RigId</th>
            <th>Status</th>
            <th>Algo / PoW</th>

            <th>CPU Brand</th>
            <th>External IP</th>
            <th>Hugepages Available</th>
            <th>Hugepages Enabled</th>
            <th>CPU is x64</th>
            <th>CPU has aes</th>
            <th>CPU is VM</th>
            <th>Hashfactor</th>
            <th>Total Pages</th>
            <th>Total Hugepages</th>
            <th>Hugepages %</th>
            <th>Free Memory (GB)</th>
            <th>Total Memory (GB)</th>
            <th>Used Threads</th>
            <th>CPU Sockets</th>
            <th>CPU Cores</th>
            <th>CPU Threads</th>
            <th>CPU L2 (MB)</th>
            <th>CPU L3 (MB)</th>
            <th>CPU nodes</th>
            <th>Max CPU usage</th>

            <th>Hashrate</th>
            <th>Hashrate 1m</th>
            <th>Hashrate 15m</th>

            <th>Hashrate Highest</th>
            <th>Hashes Total</th>
            <th>Avg. Time</th>

            <th>Shares Good</th>
            <th>Shares Total</th>
            <th>Uptime</th>
            <th>Last Update</th>
            <th>Log</th>
            <th>Edit</th>
        </tr>
        </thead>
        <tfoot>
        <tr>
            <th class="center" width="2%"><i class="fa fa-square-o" id="selectAllBottom"></i></th>
            <th class="left">Total:</th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
        </tr>
        </tfoot>
    </table>

    <br/>

    <div style="height: 30vh; margin:0 auto;">
        <canvas id="hashrateChart"></canvas>
        <br/><br/>
        <canvas id="minerChart"></canvas>
    </div>

    <div class="modal fade" id="minerEditor" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title" id="minerEditorTitle"></h4>
                </div>
                <div class="modal-body">
                    <div class="form-group" id="minerEditorViewGroup">
                        <textarea class='form-control' rows='20' id='minerEditorConfig'></textarea>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="minerEditorSave" type="button" class="btn btn-success" data-dismiss="modal">Save
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
            </div>

        </div>
    </div>

    <div class="modal fade" id="minerLogDialog" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title" id="minerLogTitle"></h4>
                </div>
                <div class="modal-body">
                    <div class="form-group" id="logViewGroup">
                        <textarea class='form-control' rows='20' id='minerLog'></textarea>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
            </div>

        </div>
    </div>

    <div class="modal fade" id="templateEditor" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Template Editor</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="templateSelector">Template:</label>
                        <select class="selectpicker form-control" id="templateSelector"></select>
                        <br/>
                        <br/>
                        <textarea class="form-control" rows='20' id="template"></textarea>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="templateEditorSave" type="button" class="btn btn-success" data-dismiss="modal">Save
                    </button>
                    <button id="templateEditorSaveAsDialog" type="button" class="btn btn-primary">Save As...</button>
                    <button id="templateEditorDeleteDialog" type="button" class="btn btn-danger" data-dismiss="modal">
                        Delete
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="templateDialogSaveAs" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Save As...</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="templateName">Template name:</label>
                        <input type="text" class="form-control" id="templateName"/>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="templateEditorSaveAs" type="button" class="btn btn-success" data-dismiss="modal">Save
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="templateDialogDelete" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Delete</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="templateName">Do you really want to delete this template?</label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="templateEditorDelete" type="button" class="btn btn-danger" data-dismiss="modal">Delete
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="commandDialogStop" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Stop Command</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="templateName">Do you really want to stop the selected miner?<br/>This will require a
                            manual restart of the daemon.</label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="commandStop" type="button" class="btn btn-danger" data-dismiss="modal">Stop</button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="resetClientStatusListDialog" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Reset</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="templateName">Do you really want to reset all client statistics?<br/>Currently
                            offline miners will be gone until they are online again.</label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="resetClientStatusList" type="button" class="btn btn-danger" data-dismiss="modal">Reset
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="assignTemplateEditor" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">Assign template</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="assignTemplateSelector">Template:</label>
                        <select class="selectpicker form-control" id="assignTemplateSelector"></select>
                        <br/><br/>
                        <label>
                            <input id="replaceWorkerId" type="checkbox" data-toggle="toggle" data-size="mini"
                                   data-onstyle="success" data-offstyle="danger" data-on="Yes" data-off="No"/>
                            <span>Replace @WORKER-ID@ with Worker-id</span>
                        </label>
                        <br/>
                        <label>
                            <input id="mergeTemplate" type="checkbox" data-toggle="toggle" data-size="mini"
                                   data-onstyle="success" data-offstyle="danger" data-on="Yes" data-off="No"/>
                            <span>Merge templates</span>
                        </label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="assignTemplate" type="button" class="btn btn-success" data-dismiss="modal">Assign
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="commandExecuteDialog" role="dialog">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close dialog-close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title" id="executeTitle"></h4>
                </div>
                <div class="modal-body">
                    <div class="form-group" id="executeViewGroup">
                        <label for="executeCommand">Script to execute:</label>
                        <textarea class='form-control' rows='10' id='executeCommand'></textarea>
                        <br/>
                        <label for='minerExecuteLog'>Execute log: [auto-refreshing]</label>
                        <textarea class='form-control' rows='10' id='minerExecuteLog'></textarea>
                    </div>
                </div>
                <div class="modal-footer">
                    <button id="commandExecuteDialogExecute" type="button" class="btn btn-success">
                        Execute
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.0/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.0/js/buttons.bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/select/1.2.4/js/dataTables.select.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.6/js/buttons.colVis.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/rowgroup/1.1.1/js/dataTables.rowGroup.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/plug-ins/1.10.16/sorting/natural.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.6.1/jquery.timeago.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>

<script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.2/js/bootstrap-select.min.js"></script>

<script src="https://use.fontawesome.com/6b3cdfc597.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-colorschemes"></script>
<script>
    const THRESHOLD_IN_MS = 60 * 1000;
    const RELOAD_INTERVAL_IN_MS = 10 * 1000;
    const CHART_RELOAD_INTERVAL_IN_MS = 60 * 1000;
    const EXECUTE_REGEX = /###START EXECUTE###(.*?)###END EXECUTE###/gs;

    let latestRelease = "";
    let currentServerTime = 0;
    let clockDrift = 0;

    let latestVersion = 0;
    let currentVersion = 0;
    let currentLogRefreshId = 0;

    function setCookie(name, value, days) {
        let expires = "";
        if (days) {
            let date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = "; expires=" + date.toUTCString();
        }
        document.cookie = name + "=" + (value.toString() || "") + expires + "; path=/";
    }

    function getCookie(name) {
        let nameEQ = name + "=";
        let ca = document.cookie.split(';');
        for (let i = 0; i < ca.length; i++) {
            let c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }

        return null;
    }

    function toggle() {
        let hideOffline = getCookie('hideOffline');
        let showOfflineNotification = getCookie('showOfflineNotification');
        let groupByAlgo = getCookie('groupByAlgo');
        if (hideOffline) {
            $("#hideOffline").prop("checked", JSON.parse(hideOffline)).trigger('change');
        }
        if (showOfflineNotification) {
            $("#showOfflineNotification").prop("checked", JSON.parse(showOfflineNotification)).trigger('change');
        }
        if (groupByAlgo) {
            $("#groupByAlgo").prop("checked", JSON.parse(groupByAlgo)).trigger('change');
        }
    }

    (function ($) {
        "use strict";

        $(function () {
            let header = $(".start-style");
            $(window).scroll(function () {
                let scroll = $(window).scrollTop();

                if (Math.floor(scroll) >= 10) {
                    header.removeClass("scroll-on").addClass('start-style');
                } else {
                    header.removeClass('start-style').addClass("scroll-on");
                }
            });

            let mode = getCookie('mode');

            toggle();

            if (mode == "light") {
                $("body").removeClass("dark");
                $("#switch").removeClass("switched");
                $("#light-mode").css("fill", "#02ABE4");
                $("#dark-mode").css("fill", "#000");
                $(".contact-item").css("color", "#171515");
                $(".navbar-brand").removeClass("dark-mode-logo");
                $(".select-checkbox").css("color", "#000");
                $(".modal-content").css("background-color", "#fff");
                $(".dialog-close").removeClass("dialog-close-scheme");
            } else {
                $("body").addClass("dark");
                $("#switch").addClass("switched");
                $("#light-mode").css("fill", "#fff");
                $("#dark-mode").css("fill", "#02ABE4");
                $(".contact-item").css("color", "#fff");
                $(".navbar-brand").addClass("dark-mode-logo");
                $(".select-checkbox").css("color", "#fff");
                $(".modal-content").css("background-color", "#1f2029");
                $(".dialog-close").addClass("dialog-close-scheme");
            }
        });

        //Animation

        $(document).ready(function () {
            $('body.xmrigCC').removeClass('xmrigCC');
        });

        //Menu On Hover

        $('body').on('mouseenter mouseleave', '.nav-item', function (e) {
            if ($(window).width() > 750) {
                let _d = $(e.target).closest('.nav-item');
                _d.addClass('show');
                setTimeout(function () {
                    _d[_d.is(':hover') ? 'addClass' : 'removeClass']('show');
                }, 1);
            }
        });

        $('#hideOffline').change(function () {
            setCookie('hideOffline', $(this).prop('checked'), 90);
        });

        $('#showOfflineNotification').change(function () {
            setCookie('showOfflineNotification', $(this).prop('checked'), 90);
        });

        $('#groupByAlgo').change(function () {
            setCookie('groupByAlgo', $(this).prop('checked'), 90);
        });

        //Switch light/dark

        $("#switch").on('click', function () {
            if ($("body").hasClass("dark")) {
                $("body").removeClass("dark");
                $("#switch").removeClass("switched");
                $("#light-mode").css("fill", "#02ABE4");
                $("#dark-mode").css("fill", "#000");
                $("#github").css("color", "#171515");
                $(".navbar-brand").removeClass("dark-mode-logo");
                $(".select-checkbox").css("color", "#000");
                $(".modal-content").css("background-color", "#fff");
                $(".dialog-close").removeClass("dialog-close-scheme");
                setCookie('mode', 'light', 90);
            } else {
                $("body").addClass("dark");
                $("#switch").addClass("switched");
                $("#light-mode").css("fill", "#fff");
                $("#dark-mode").css("fill", "#02ABE4");
                $("#github").css("color", "#fff");
                $(".navbar-brand").addClass("dark-mode-logo");
                $(".select-checkbox").css("color", "#fff");
                $(".modal-content").css("background-color", "#202020");
                $(".dialog-close").addClass("dialog-close-scheme");
                setCookie('mode', 'dark', 90)
            }
        });

    })(jQuery);

    document.onreadystatechange = function () {
        let state = document.readyState
        if (state == 'interactive') {
            document.getElementById('loader-parent').style.display = "none";
            document.getElementById('loader-parent').style.visibility = "hidden";
        } else if (state == 'complete') {
            setTimeout(function () {
                document.getElementById('loader-parent').style.display = "none";
                document.getElementById('loader-parent').style.height = "0";
                document.getElementById('loader-parent').style.visibility = "hidden";
            }, 3000);

        }
    }


    $.fn.dataTable.ext.search.push(
        function (settings, searchData, index, rowData, counter) {

            let hideOffline = $('#hideOffline').prop('checked');
            let showNotification = $('#showOfflineNotification').prop('checked');

            let clientId = rowData.client_status.client_id;
            let lastStatus = rowData.client_status.last_status_update * 1000;

            let online = isOnline(lastStatus);

            if (!online) {
                let threshold = currentServerTime - (THRESHOLD_IN_MS + RELOAD_INTERVAL_IN_MS);
                if (lastStatus > threshold && showNotification) {
                    $("#notificationBar").after('<div class="alert alert-danger alert-dismissable fade in">' +
                        '<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>' +
                        '<strong>Miner ' + clientId + ' just went offline!</strong> Last update: ' + new Date(lastStatus) +
                        '</div>');
                }
            }

            return (online || !hideOffline);
        }
    );


    $(document).ready(function () {
        let table = $('#clientStatusList').DataTable({
            dom: "<'row'<'col-sm-12'B>><'row rowPadded'<'col-sm-9'l><'col-sm-3'f>><'row'<'col-sm-12't>><'row'<'col-sm-4'i><'col-sm-8'p>><'col-sm-13'<'#serverTime'>>",
            lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
            pageLength: -1,
            bPpaginate: true,
            pagingType: "full_numbers",
            stateSave: true,
            ajax: {
                url: "/admin/getClientStatusList",
                dataSrc: function (data) {
                    return JSON.parse(htmlEncode(JSON.stringify(data.client_status_list)));
                }
            },
            orderFixed: [8, 'asc'], //algo
            columnDefs: [
                {type: 'natural', targets: 1}
            ],
            rowGroup: {
                dataSrc: function (data) {
                    return JSON.parse(htmlEncode(JSON.stringify(data.client_status.current_algo_name)));
                },
                endRender: null,
                startRender: function (rows, group) {
                    return $('<tr/>')
                        .append('<td colspan=' + table.columns().header().length + ' style="color: #000">' + group + '</td>')
                },
            },
            columns: [
                {
                    data: null,
                    defaultContent: '',
                    className: 'select-checkbox',
                    // render: checkbox,
                    orderable: false
                },
                {data: "client_status.client_id", render: clientInfo},
                {data: "client_status.version", render: version},
                {data: "client_status.current_pool"},
                {data: "client_status.current_pool_user", visible: false},
                {data: "client_status.current_pool_pass", visible: false},
                {data: "client_status.current_pool_rig_id", visible: false},
                {data: "client_status.current_status", render: clientStatus},
                {data: "client_status.current_algo_name", render: algoAndPowVariantName},

                {data: "client_status.cpu_brand", visible: false},
                {data: "client_status.external_ip", visible: false},
                {data: "client_status.hugepages_available", visible: false},
                {data: "client_status.hugepages_enabled", visible: false},
                {data: "client_status.cpu_is_x64", visible: false},
                {data: "client_status.cpu_has_aes", visible: false},
                {data: "client_status.cpu_is_vm", visible: false},
                {data: "client_status.hash_factor", className: "right", visible: false},
                {data: "client_status.total_pages", className: "right", visible: false},
                {data: "client_status.total_hugepages", className: "right", visible: false},
                {data: null, render: clientHPpercent, className: "right", visible: false},
                {data: "client_status.free_memory", render: memory, className: "right", visible: false},
                {data: "client_status.total_memory", render: memory, className: "right", visible: false},
                {data: "client_status.current_threads", className: "right", visible: false},
                {data: "client_status.cpu_sockets", className: "right", visible: false},
                {data: "client_status.cpu_cores", className: "right", visible: false},
                {data: "client_status.cpu_threads", className: "right", visible: false},
                {data: "client_status.cpu_l2", render: cache, className: "right", visible: false},
                {data: "client_status.cpu_l3", render: cache, className: "right", visible: false},
                {data: "client_status.cpu_nodes", className: "right", visible: false},
                {data: "client_status.max_cpu_usage", render: percent, className: "right", visible: false},

                {data: "client_status.hashrate_short", render: round, className: "right"},
                {data: "client_status.hashrate_medium", render: round, className: "right"},
                {data: "client_status.hashrate_long", render: round, className: "right"},
                {data: "client_status.hashrate_highest", render: round, className: "right"},
                {data: "client_status.hashes_total", className: "right"},
                {data: "client_status.avg_time", className: "right"},
                {data: "client_status.shares_good", className: "right"},
                {data: "client_status.shares_total", className: "right"},
                {data: "client_status.uptime", render: uptime, className: "right"},
                {data: "client_status.last_status_update", render: laststatus},
                {
                    data: null,
                    defaultContent:
                        "<td class='center-tab'><button type='button' id='LOG' class='btn btn-xs btn-info' data-toggle='tooltip' title='View miner log'><i class='fa fa-file-text-o'></i></button></td>",
                    orderable: false,
                    className: "center-tab"
                },
                {
                    data: null,
                    defaultContent:
                        "<td class='center-tab'><button type='button' id='EDIT' class='btn btn-xs btn-primary' data-toggle='tooltip' title='Edit miner config'><i class='fa fa-edit'></i></button></td>",
                    orderable: false,
                    className: "center-tab"
                }
            ],
            rowId: 'client_status.client_id',
            select: {
                style: "multi+shift"
            },
            order: [1, 'asc'], // workerid
            buttons: [
                'colvis',
                {
                    text: '<i class="fa fa-upload"> Push miner config</i>',
                    className: 'btn-info',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("UPDATE_CONFIG", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-download"> Pull miner config</i>',
                    className: 'btn-primary',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("PUBLISH_CONFIG", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-recycle"> Update miner</i>',
                    className: 'btn-danger',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("UPDATE", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-table"> Assign template</i>',
                    className: 'btn-info',
                    enabled: false,
                    action: function () {
                        $.ajax({
                            type: "GET",
                            url: "/admin/getClientConfigTemplates",
                            dataType: "json",
                            success: function (data) {
                                let htmlContent = "";

                                let arrayLength = data["templates"].length;
                                for (let i = 0; i < arrayLength; i++) {
                                    htmlContent += "<option>" + data["templates"][i] + "</option>";
                                }

                                if (arrayLength > 0) {
                                    $('#assignTemplate').prop('disabled', false);

                                    $('#assignTemplateSelector').html(htmlContent);
                                    $('#assignTemplateSelector').selectpicker('refresh');
                                } else {
                                    $('#assignTemplate').prop('disabled', true);
                                }

                                $('#assignTemplateEditor').modal('show');
                            },
                            error: function (data) {
                                setError('<strong>Unable to fetch templates</strong> - Please make they exist!');
                            }
                        });
                    }
                },
                {
                    text: '<i class="fa fa-edit"> Template Editor</i>',
                    className: 'btn-primary',
                    enabled: true,
                    action: function () {
                        $.ajax({
                            type: "GET",
                            url: "/admin/getClientConfigTemplates",
                            dataType: "json",
                            success: function (data) {
                                let htmlContent = "";

                                let arrayLength = data["templates"].length;
                                for (let i = 0; i < arrayLength; i++) {
                                    htmlContent += "<option>" + data["templates"][i] + "</option>";
                                }

                                if (arrayLength > 0) {
                                    $('#templateEditorSave').prop('disabled', false);
                                    $('#templateEditorDeleteDialog').prop('disabled', false);

                                    $('#templateSelector').html(htmlContent);
                                    $('#templateSelector').selectpicker('refresh');
                                    $('#templateSelector').trigger('change');
                                } else {
                                    $('#templateEditorSave').prop('disabled', true);
                                    $('#templateEditorDeleteDialog').prop('disabled', true);
                                }

                                $('#templateEditor').modal('show');
                            },
                            error: function (data) {
                                setError('<strong>Unable to fetch templates</strong> - Please make they exist!');
                            }
                        });
                    }
                },
                {
                    text: '<i class="fa fa-play"> Start</i>',
                    className: 'btn-success',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("START", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-pause"> Pause</i>',
                    className: 'btn-warning',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("STOP", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-sign-out"> Stop</i>',
                    className: 'btn-danger',
                    enabled: false,
                    action: function () {
                        $('#commandDialogStop').modal('show');
                    }
                },
                {
                    text: '<i class="fa fa-repeat"> Restart</i>',
                    className: 'btn-info',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("RESTART", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-refresh"> Reboot</i>',
                    className: 'btn-danger',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            sendAction("REBOOT", data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-trash-o"> Remove</i>',
                    className: 'btn-warning',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            removeClientStatus(data.client_status.client_id);
                        });
                    }
                },
                {
                    text: '<i class="fa fa-rocket"> Execute</i>',
                    className: 'btn-primary',
                    enabled: false,
                    action: function () {
                        table.rows({selected: true}).eq(0).each(function (index) {
                            let row = table.row(index);
                            let data = row.data();

                            $('#executeViewGroup').data("clientId", data.client_status.client_id);
                            $('#executeTitle').html("Shell execute for Miner: " + data.client_status.client_id + " (" + data.client_status.external_ip + ")");

                            loadClientLog($('#minerExecuteLog'), data.client_status.client_id, function (data) {
                                let result;
                                Array.from(data.match(EXECUTE_REGEX)).forEach(item => {
                                    result = item + '\n';
                                });

                                return result.trim();
                            });

                            $('#commandExecuteDialog').modal('show');
                        });
                    }
                }
            ],

            "footerCallback": function (row, data, start, end, display) {
                let api = this.api();

                let sumHashrateShort = 0;
                let sumHashrateMedium = 0;
                let sumHashrateLong = 0;
                let sumHashrateHighest = 0;
                let sumHashesTotal = 0;
                let avgTimeTotal = 0;
                let sumSharesGood = 0;
                let sumSharedTotal = 0;

                let colOffset = 30;

                sumHashrateShort = api
                    .column(colOffset, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumHashrateMedium = api
                    .column(colOffset + 1, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumHashrateLong = api
                    .column(colOffset + 2, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumHashrateHighest = api
                    .column(colOffset + 3, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumHashesTotal = api
                    .column(colOffset + 4, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                avgTimeTotal = api
                    .column(colOffset + 5, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return (a + b);
                    }, 0) / api.column(26, {page: 'current'}).data().length;

                sumSharesGood = api
                    .column(colOffset + 6, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumSharedTotal = api
                    .column(colOffset + 7, {page: 'current'})
                    .data()
                    .reduce(function (a, b) {
                        return a + b;
                    }, 0);

                sumHashrateShort = round(sumHashrateShort);
                sumHashrateMedium = round(sumHashrateMedium);
                sumHashrateLong = round(sumHashrateLong);
                sumHashrateHighest = round(sumHashrateHighest);
                avgTimeTotal = round(avgTimeTotal);

                // update footer
                $(api.column(colOffset).footer()).html(sumHashrateShort);
                $(api.column(colOffset + 1).footer()).html(sumHashrateMedium);
                $(api.column(colOffset + 2).footer()).html(sumHashrateLong);
                $(api.column(colOffset + 3).footer()).html(sumHashrateHighest);
                $(api.column(colOffset + 4).footer()).html(sumHashesTotal);
                $(api.column(colOffset + 5).footer()).html(avgTimeTotal);
                $(api.column(colOffset + 6).footer()).html(sumSharesGood);
                $(api.column(colOffset + 7).footer()).html(sumSharedTotal);
            }
        });

        table.on('xhr.dt', function (e, settings, json, xhr) {
            // check version
            if (latestRelease === "" && json !== undefined) {
                $.ajax({
                    url: "https://api.github.com/repos/Bendr0id/xmrigCC/releases/latest",
                    type: 'GET',
                    dataType: "json",
                    success: function (release) {
                        latestRelease = release.tag_name
                        latestVersion = parseInt(release.tag_name.split('.').join(""));
                        currentVersion = parseInt(json.current_version.split('.').join(""));

                        if (currentVersion < 1000) {
                            currentVersion = currentVersion * 10;
                        }

                        if (latestVersion < 1000) {
                            latestVersion = latestVersion * 10;
                        }

                        if (latestVersion > currentVersion) {
                            $("#updateNotificationBar").html('<div class="alert alert-info alert-dismissable fade in">' +
                                '<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>' +
                                '<a href="https://github.com/Bendr0id/xmrigCC/releases/latest"><strong>Update!</strong> XMRigCC v' + latestRelease + ' is available for download\n</a>' +
                                '</div>');
                        }
                    }
                });
            }

            currentServerTime = settings.json.current_server_time * 1000;
            clockDrift = new Date().getTime() - currentServerTime;

            $('#serverTime').html("<div class='dataTables_info text-right'>" + new Date(currentServerTime) + "</div>");
        });

        table.on('init', function () {
            if ($('#groupByAlgo').prop('checked')) {
                table.rowGroup().enable().draw();
                table.order.fixed({
                    pre: [8, 'asc'] // algo
                }).draw();
            } else {
                table.rowGroup().disable().draw();
                table.order.fixed({
                    pre: []
                }).draw();
            }
        });

        table.on('select', function () {
            let selectedRows = table.rows({selected: true}).count();
            for (let i = 1; i < 13; i++) {
                if (i === 12) {
                    table.button(i).enable(selectedRows === 1);
                }
                else {
                    table.button(i).enable(selectedRows > 0 || i === 5);
                }
            }
        });

        table.on('deselect', function () {
            let selectedRows = table.rows({selected: true}).count();

            for (let i = 1; i < 13; i++) {
                table.button(i).enable(selectedRows > 0 || i === 5);
            }
        });

        table.buttons().container().appendTo('#clientStatusList_wrapper .col-sm-6:eq(0)');

        $('#hideOffline').change(function () {
            table.draw();
        });

        $('#groupByAlgo').change(function () {
            if ($('#groupByAlgo').prop('checked')) {
                table.rowGroup().enable().draw();
                table.order.fixed({
                    pre: [8, 'asc'] // algo
                }).draw();
            } else {
                table.rowGroup().disable().draw();
                table.order.fixed({
                    pre: []
                }).draw();
            }
        });

        $('#resetClientStatus').click(function () {
            $('#resetClientStatusListDialog').modal('show');
        });

        $('#resetClientStatusList').click(function () {
            resetClientStatusList();
        });

        $('#clientStatusList tbody ').on('click', 'button#EDIT', function () {
            let data = table.row($(this).parents('tr')).data();
            let clientId = data['client_status']['client_id'];
            let clientIp = data['client_status']['external_ip'];

            $.ajax({
                type: "GET",
                url: "/admin/getClientConfig?clientId=" + htmlDecode(clientId),
                dataType: "json",
                success: function (jsonClientConfig) {
                    $('#minerEditorViewGroup').data("clientId", clientId);
                    $('#minerEditorTitle').html("Config of Miner: " + clientId + " (" + clientIp + ")");
                    $('#minerEditorConfig').html(htmlEncode(JSON.stringify(jsonClientConfig, undefined, 2)));

                    $('#minerEditor').modal('show');
                },
                error: function (data) {
                    setError('<strong>Unable to fetch ' + clientId + '_config.json</strong> - Please make sure that you pulled the config before!');
                }
            });
        });

        $('#minerEditorSave').click(function (event) {
            let clientId = $('#minerEditorViewGroup').data("clientId");
            let clientConfig = $('#minerEditorConfig').val();

            setClientConfig(clientId, clientConfig);
        });

        $('#templateEditorSave').click(function (event) {
            let templateId = htmlEncode($('#templateSelector').val());
            let template = $('#template').val();

            setTemplateConfig(templateId, template);
        });

        $('#templateEditorSaveAsDialog').click(function (event) {
            $('#templateDialogSaveAs').modal('show');
        });

        $('#templateEditorDeleteDialog').click(function (event) {
            $('#templateDialogDelete').modal('show');
        });

        $('#templateEditorSaveAs').click(function (event) {
            let templateId = htmlEncode($('#templateName').val());
            let template = $('#template').val();

            setTemplateConfig(templateId, template);

            $('#templateEditor').modal('hide');
        });

        $('#templateEditorDelete').click(function (event) {
            let templateId = htmlEncode($('#templateSelector').val());

            deleteTemplateConfig(templateId, template);
        });

        $('#commandStop').click(function (event) {
            table.rows({selected: true}).eq(0).each(function (index) {
                let row = table.row(index);
                let data = row.data();

                sendAction("SHUTDOWN", data.client_status.client_id);
            });
        });

        $('#commandExecuteDialogExecute').click(function (event) {
            let command = $('#executeCommand').val().trim();
            let clientId = $('#executeViewGroup').data("clientId");

            sendAction("EXECUTE", clientId, command);
        });

        $('#clientStatusList tbody').on('click', 'button#LOG', function () {
            let data = table.row($(this).parents('tr')).data();
            let clientId = data['client_status']['client_id'];
            let clientIp = data['client_status']['external_ip'];

            $('#logViewGroup').data("clientId", clientId);
            $('#minerLogTitle').html("Log of Miner: " + clientId + " (" + clientIp + ") [auto-refreshing]");

            loadClientLog($('#minerLog'), clientId, function (data) {
                return data.replace(EXECUTE_REGEX, "[truncated]").trim();
            });

            $('#minerLogDialog').modal('show');
        });

        $('#minerLogDialog').on('shown.bs.modal', function () {
            let clientId = $('#logViewGroup').data("clientId");

            currentLogRefreshId = setInterval(function () {
                loadClientLog($('#minerLog'), clientId, function (data) {
                    return data.replace(EXECUTE_REGEX, "[truncated]").trim();
                });
            }, RELOAD_INTERVAL_IN_MS);
        });

        $('#minerLogDialog').on('hidden.bs.modal', function () {
            clearInterval(currentLogRefreshId);
        });

        $('#commandExecuteDialog').on('shown.bs.modal', function () {
            let clientId = $('#executeViewGroup').data("clientId");

            currentLogRefreshId = setInterval(function () {
                loadClientLog($('#minerExecuteLog'), clientId, function (data) {
                    let result;
                    Array.from(data.match(EXECUTE_REGEX)).forEach(item => {
                        result = item + '\n';
                    });

                    return result.trim();
                });
            }, RELOAD_INTERVAL_IN_MS);
        });

        $('#commandExecuteDialog').on('hidden.bs.modal', function () {
            clearInterval(currentLogRefreshId);
        });

        $('#templateSelector').on('changed.bs.select', function (e, clickedIndex, newValue, oldValue) {
            let selected = $(e.currentTarget).val();
            $.ajax({
                type: "GET",
                url: "/admin/getClientConfig?clientId=template_" + htmlDecode(selected),
                dataType: "json",
                success: function (jsonClientConfig) {
                    $('#template').html(htmlEncode(JSON.stringify(jsonClientConfig, undefined, 2)));
                },
                error: function (data) {
                    setError('<strong>Unable to fetch template ' + selected + '</strong> - Please make sure it readable!');
                }
            });
        });

        $('#assignTemplate').click(function (event) {
            let template = $('#assignTemplateSelector').val();
            $.ajax({
                type: "GET",
                url: "/admin/getClientConfig?clientId=template_" + htmlDecode(template),
                dataType: "json",
                success: function (jsonTemplate) {
                    table.rows({selected: true}).eq(0).each(function (index) {
                        let row = table.row(index);
                        let data = row.data();
                        let clientId = data['client_status']['client_id'];

                        if ($('#mergeTemplate').prop('checked')) {
                            setMergedClientConfig(jsonTemplate, clientId);
                        } else {
                            jsonTemplate['cc-client']['worker-id'] = htmlDecode(clientId);

                            clientConfig = JSON.stringify(jsonTemplate, undefined, 2);

                            if ($('#replaceWorkerId').prop('checked')) {
                                clientConfig = clientConfig.replace(new RegExp("@WORKER-ID@", 'g'), htmlDecode(clientId)).trim();
                            }

                            setClientConfig(clientId, clientConfig);
                        }
                    });
                },
                error: function (data) {
                    setError('<strong>Unable to fetch template ' + template + '</strong> - Please make sure it readable!');
                }
            });
        });

        $('#selectAllTop,#selectAllBottom').click(function () {
            if ($("#selectAllTop").hasClass("fa fa-square-o")) {
                $("#selectAllTop").removeClass("fa fa-square-o").addClass("fa fa-check-square-o");
                $("#selectAllBottom").removeClass("fa fa-square-o").addClass("fa fa-check-square-o");

                table.rows().select();
            } else {
                $("#selectAllTop").removeClass("fa fa-check-square-o").addClass("fa fa-square-o");
                $("#selectAllBottom").removeClass("fa fa-check-square-o").addClass("fa fa-square-o");

                table.rows().deselect();
            }
        });


        let hashrateChart = new Chart(document.getElementById("hashrateChart").getContext("2d"), {
            type: "line",
            data: {
                datasets: []
            },
            options: {
                title: {
                    display: true,
                    text: 'Hashrates'
                },
                tooltips: {
                    mode: 'nearest',
                    intersect: false,
                },
                legend: {
                    display: true,
                    position: 'top',
                    labels: {
                        generateLabels: function (chart) {
                            let data = chart.data;
                            return Chart.helpers.isArray(data.datasets) ? data.datasets.map(function (dataset, i) {
                                let total = 0;
                                dataset.data.forEach(item => {
                                    total += item.y;
                                });

                                let avg = (dataset.data.length > 0) ? (total / dataset.data.length).toFixed(2) : 0;
                                return {
                                    text: dataset.label + " (avg.: " + avg + " h/s)",
                                    fillStyle: (!Chart.helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
                                    hidden: !chart.isDatasetVisible(i),
                                    lineCap: dataset.borderCapStyle,
                                    lineDash: dataset.borderDash,
                                    lineDashOffset: dataset.borderDashOffset,
                                    lineJoin: dataset.borderJoinStyle,
                                    lineWidth: dataset.borderWidth,
                                    strokeStyle: dataset.borderColor,
                                    pointStyle: dataset.pointStyle,

                                    // Below is extra data used for toggling the datasets
                                    datasetIndex: i
                                };
                            }, this) : [];
                        },
                    },
                },
                scales: {
                    yAxes: [
                        {
                            id: 'hashrate',
                            position: 'left',
                            scalePositionLeft: true,
                            stacked: false,
                            ticks: {
                                beginAtZero: true
                            },
                            scaleLabel: {
                                display: true,
                                labelString: 'Hashrate',
                                fontSize: 16
                            }
                        }
                    ],
                    xAxes: [{
                        type: 'time',
                        distribution: 'series',
                        time: {
                            unit: 'minute',
                            displayFormats: {
                                minute: 'HH:mm'
                            }
                        },
                        ticks: {
                            stepSize: 10,
                            autoSkip: true,
                            maxTicksLimit: 60
                        }
                    }]
                },
                elements: {
                    point: {
                        radius: 0
                    }
                },
                responsive: true,
                maintainAspectRatio: false
            },
            plugins: {
                colorschemes: {
                    scheme: 'brewer.Paired12'
                }
            }
        });

        let minerChart = new Chart(document.getElementById("minerChart").getContext("2d"), {
            type: "line",
            data: {
                datasets: []
            },
            options: {
                title: {
                    display: true,
                    text: 'Miners'
                },
                tooltips: {
                    mode: 'nearest',
                    intersect: false,
                },
                scales: {
                    yAxes: [
                        {
                            id: 'miner',
                            position: 'left',
                            scalePositionLeft: true,
                            stacked: false,
                            ticks: {
                                beginAtZero: true,
                                callback: function (value) {
                                    if (value % 1 === 0) {
                                        return value;
                                    }
                                }
                            },
                            scaleLabel: {
                                display: true,
                                labelString: 'Miner',
                                fontSize: 16
                            }
                        }
                    ],
                    xAxes: [{
                        type: 'time',
                        distribution: 'series',
                        time: {
                            unit: 'minute',
                            displayFormats: {
                                minute: 'HH:mm'
                            }
                        },
                        ticks: {
                            stepSize: 10,
                            autoSkip: true,
                            maxTicksLimit: 60
                        }
                    }]
                },
                elements: {
                    point: {
                        radius: 0
                    }
                },
                responsive: true,
                maintainAspectRatio: false
            },
            plugins: {
                colorschemes: {
                    scheme: 'brewer.Paired12'
                }
            }
        });

        Chart.plugins.register({
            afterDraw: function (chart) {
                if (chart.data.datasets.length === 0) {
                    // No data is present
                    let ctx = chart.chart.ctx;
                    let width = chart.chart.width;
                    let height = chart.chart.height

                    ctx.save();
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.font = "16px normal 'Helvetica Nueue'";
                    ctx.fillText('No data to display', width / 2, height / 2);
                    ctx.restore();
                }
            }
        });

        updateCharts(hashrateChart, minerChart);

        setInterval(function () {
            table.ajax.reload(null, false);
        }, RELOAD_INTERVAL_IN_MS);

        setInterval(function () {
            updateCharts(hashrateChart, minerChart);
        }, CHART_RELOAD_INTERVAL_IN_MS);
    });

    function clientHPpercent(data, type, row) {
        if (!row.client_status.hugepages_enabled || row.client_status.total_pages == 0) return 0;
        return Math.round(1000 * row.client_status.total_hugepages / row.client_status.total_pages) / 10;
    }

    function percent(data, type, row) {
        if (row.client_status.max_cpu_usage === -1) {
            return 100;
        } else {
            return row.client_status.max_cpu_usage;
        }
    }

    function loadClientLog(targetItem, clientId, filterHandler) {
        $.ajax({
            type: "GET",
            url: "/admin/getClientLog?clientId=" + htmlDecode(clientId),
            dataType: "json",
            success: function (data) {
                let cleanLog = filterHandler(htmlEncode(data.client_log));
                targetItem.html(cleanLog).show();
            },
            error: function (data) {
                setError('<strong>Unable to fetch ' + clientId + ' log.</strong> - Please make sure it is enabled on the miner!');
            }
        });
    }

    function sendAction(action, clientId, payload) {
        let payloadContent = payload == null ? '' : ' [payload=' + htmlEncode(payload) + ']';
        $.ajax({
            type: "POST",
            url: "/admin/setClientCommand?clientId=" + htmlDecode(clientId),
            dataType: "text",
            data: '{"control_command":{"command": "' + action + '", "payload": ' + JSON.stringify(payload == null ? "" : payload) + '}}',
            success: function (data) {
                setSuccess('<strong>Successfully send ' + action + ' to ' + clientId + payloadContent + '</strong> - It can take up to 30s until the command is processed.');
            },
            error: function (data) {
                setError('<strong>Failed to send ' + action + ' to ' + clientId + payloadContent + '</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function removeClientStatus(clientId) {
        $.ajax({
            type: "POST",
            url: "/admin/removeClientStatus?clientId=" + htmlDecode(clientId),
            dataType: "text",
            data: '',
            success: function (data) {
                setSuccess('<strong>Successfully send the removed client status request to the Server.</strong> - Now just wait for the next refresh.');
            },
            error: function (data) {
                setError('<strong>Failed to send the removed client status request to the Server.</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function resetClientStatusList() {
        $.ajax({
            type: "POST",
            url: "/admin/resetClientStatusList",
            dataType: "text",
            data: '{}',
            success: function (data) {
                setSuccess('<strong>Successfully send the reset client status list request to the Server.</strong> - Now just wait for the next refresh.');
            },
            error: function (data) {
                setError('<strong>Failed to send the reset client status list request to the Server.</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function uptime(data, type, row) {
        if (type !== 'sort') {
            let lastStatus = row.client_status.last_status_update * 1000;

            if (isOnline(lastStatus)) {
                return numeral(data / 1000).format('00:00:00:00');
            } else {
                return "";
            }
        }

        return data;
    }

    function setMergedClientConfig(template, clientId) {
        $.ajax({
            type: "GET",
            url: "/admin/getClientConfig?clientId=" + htmlDecode(clientId),
            dataType: "json",
            success: function (clientConfig) {
                $.extend(true, clientConfig, template);

                clientConfig = JSON.stringify(clientConfig, undefined, 2)

                if ($('#replaceWorkerId').prop('checked')) {
                    clientConfig = clientConfig.replace(new RegExp("@WORKER-ID@", 'g'), htmlDecode(clientId)).trim();
                }

                setClientConfig(clientId, clientConfig);
            },
            error: function (data) {
                setError('<strong>Unable to fetch client config ' + clientId + ' for template merge</strong> - Please make sure it readable!');
            }
        });
    }

    function laststatus(data, type, row) {
        if (type !== 'sort') {
            let date = new Date(data * 1000 - clockDrift);
            return '<span data-toggle="tooltip" title="' + date + '">' + jQuery.timeago(date) + '</span>';
        }

        return data;
    }

    function algoAndPowVariantName(data, type, row) {
        let algo = row.client_status.current_algo_name;
        let powVariant = row.client_status.current_pow_variant_name;

        if (powVariant !== "") {
            return algo + " / " + powVariant
        } else {
            return algo;
        }
    }

    function version(data, type, row) {
        let clientVersion = parseInt(row.client_status.version.split('.').join(""));

        if (clientVersion < 1000) {
            clientVersion = clientVersion * 10;
        }

        if (latestVersion > clientVersion) {
            return '<span data-toggle="tooltip" title="Outdated"><div class="offline">' + data + '</div></span>';
        } else {
            return data;
        }
    }

    function clientStatus(data, type, row) {
        let lastStatus = row.client_status.last_status_update * 1000;

        if (isOnline(lastStatus)) {
            return data;
        } else {
            return "OFFLINE";
        }
    }

    function checkbox(data, type, row) {
        return '<div class="select-checkbox"><input type="checkbox"><div>'
    }

    function clientInfo(data, type, row) {
        if (type !== 'sort') {
            let lastStatus = row.client_status.last_status_update * 1000;
            let online = isOnline(lastStatus);

            let tooltip = "CPU: " + row.client_status.cpu_brand + " (" + row.client_status.cpu_sockets + ") [" + row.client_status.cpu_cores + " cores / " + row.client_status.cpu_threads + " threads]";
            tooltip += '\n';
            tooltip += "CPU Flags: " + (row.client_status.cpu_has_aes ? "AES-NI " : "");
            tooltip += (row.client_status.cpu_is_x64 ? "x64 " : "");
            tooltip += (row.client_status.cpu_is_vm ? "VM" : "");
            tooltip += '\n';
            tooltip += "CPU Cache L2/L3: " + cache(row.client_status.cpu_l2) + " MB/" + cache(row.client_status.cpu_l3) + " MB";
            tooltip += '\n';
            tooltip += "CPU Nodes: " + row.client_status.cpu_nodes;
            tooltip += '\n';
            tooltip += "Max CPU usage: " + (row.client_status.max_cpu_usage > 0 ? row.client_status.max_cpu_usage : "100") + "%";
            tooltip += '\n';
            tooltip += "Huge Pages: " + (row.client_status.hugepages_available ? " available, " : " unavailable, ");
            tooltip += (row.client_status.hugepages_enabled ? "enabled (" + row.client_status.total_hugepages + "/" + row.client_status.total_pages + ")" : "disabled");
            tooltip += '\n';
            tooltip += "Used Threads: " + row.client_status.current_threads;
            tooltip += (row.client_status.hash_factor > 1 ? " [" + row.client_status.hash_factor + "x multi hash mode]" : "");
            tooltip += '\n';
            tooltip += "Memory Free/Total: " + memory(row.client_status.free_memory) + " GB/" + memory(row.client_status.total_memory) + " GB";
            tooltip += '\n';

            if (row.client_status.gpu_info_list) {
                for (let id in row.client_status.gpu_info_list) {
                    tooltip += "GPU #" + row.client_status.gpu_info_list[id].gpu_info.device_idx + ": ";
                    tooltip += row.client_status.gpu_info_list[id].gpu_info.name + ", "
                    tooltip += "intensity: " + row.client_status.gpu_info_list[id].gpu_info.raw_intensity + " ";
                    tooltip += "(" + row.client_status.gpu_info_list[id].gpu_info.work_size + "/" + row.client_status.gpu_info_list[id].gpu_info.max_work_size + "), ";
                    tooltip += "cu: " + row.client_status.gpu_info_list[id].gpu_info.compute_units;
                    tooltip += '\n';
                }
            }

            tooltip += "Client IP: " + row.client_status.external_ip;
            tooltip += '\n';
            tooltip += "Version: " + row.client_status.version;
            tooltip += '\n';
            tooltip += "Status: " + online ? "Online" : "Offline";

            if (online) {
                return '<span data-toggle="tooltip" title="' + tooltip + '"><div class="online">' + data + '</div></span>';
            } else {
                return '<span data-toggle="tooltip" title="' + tooltip + '"><div class="offline">' + data + '</div></span>';
            }
        }

        return data;
    }

    function round(data, type, row) {
        return Math.round(data * 100) / 100;
    }

    function memory(data, type, row) {
        return Math.round(data / 1024 / 1024 / 1024 * 10) / 10;
    }

    function cache(data, type, row) {
        return Math.round(data / 1024 * 100) / 100;
    }

    function isOnline(lastStatus) {
        let threshold = currentServerTime - THRESHOLD_IN_MS;
        if (lastStatus > threshold) {
            return true;
        } else {
            return false;
        }
    }

    function setSuccess(info) {
        $("#statusBar").after('<div class="alert alert-success" role="alert">' +
            '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
            info + '</div>');

        window.setTimeout(function () {
            $(".alert-success").fadeTo(500, 0).slideUp(500, function () {
                $(".alert-success").alert('close');
            });
        }, 5000);
    }

    function setError(error) {
        $("#statusBar").after('<div class="alert alert-danger" role="alert">' +
            '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
            error + '</div>');

        window.setTimeout(function () {
            $(".alert-danger").fadeTo(500, 0).slideUp(500, function () {
                $(".alert-danger").alert('close');
            });
        }, 10000);
    }

    function setClientConfig(clientId, clientConfig) {
        $.ajax({
            url: "/admin/setClientConfig?clientId=" + htmlDecode(clientId),
            type: 'POST',
            dataType: "text",
            data: clientConfig,
            success: function (data) {
                setSuccess('<strong>Successfully updated config for: ' + clientId + '</strong> - You need push the config to the miner to apply the config.');
            },
            error: function (data) {
                setError('<strong>Failed to update config for: ' + clientId + '</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function setTemplateConfig(templateId, templateConfig) {
        $.ajax({
            url: "/admin/setClientConfig?clientId=template_" + htmlDecode(templateId),
            type: 'POST',
            dataType: "text",
            data: templateConfig,
            success: function (data) {
                setSuccess('<strong>Successfully stored template: ' + templateId + '</strong> - You need to assign it to miners to apply.');
            },
            error: function (data) {
                setError('<strong>Failed to store template: ' + templateId + '</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function deleteTemplateConfig(templateId) {
        $.ajax({
            url: "/admin/deleteClientConfig?clientId=template_" + htmlDecode(templateId),
            type: 'POST',
            dataType: "text",
            data: '{}',
            success: function (data) {
                setSuccess('<strong>Successfully deleted template: ' + templateId + '</strong>');
            },
            error: function (data) {
                setError('<strong>Failed to delete template: ' + templateId + '</strong> \nError: ' + JSON.stringify(data, undefined, 2));
            }
        });
    }

    function updateCharts(hashrateChart, minerChart) {

        $.ajax({
            url: '/admin/getClientStatistics',
            dataType: 'json',
        }).done(function (results) {

            let algos = results["client_statistics"].map(function (e) {
                return e.algo;
            });

            let statistics = results["client_statistics"].map(function (e) {
                return e.statistics;
            });

            let hashrateDatasets = [], minerDatasets = [];
            for (let j = 0; j < results["client_statistics"].length; j++) {
                let hashrates = statistics[j].map(function (e) {
                    return {
                        x: new Date(e.timestamp),
                        y: Math.round(e.hashrate * 100) / 100
                    }
                });

                let miners = statistics[j].map(function (e) {
                    return {
                        x: new Date(e.timestamp),
                        y: e.miner
                    }
                });

                hashrateDatasets.push({label: algos[j], type: 'line', data: hashrates, spanGraphs: false, fill: true});
                minerDatasets.push({label: algos[j], type: 'line', data: miners, spanGraphs: false, fill: false});
            }

            hashrateChart.data.datasets = hashrateDatasets;
            hashrateChart.update();

            minerChart.data.datasets = minerDatasets;
            minerChart.update();
        });
    }

    function htmlDecode(input) {
        let doc = new DOMParser().parseFromString(input, "text/html");
        return doc.documentElement.textContent;
    }

    function htmlEncode(input) {
        return input.replaceAll("&", "&amp;")
            .replaceAll("<", "&lt;")
            .replaceAll(">", "&gt;");
    }
</script>
</body>
</html>
